// 消息接收接口
#include <stdio.h>
#include "control.h"
#include "gdevice.h"
#include "msg_queue.h"
#include "global.h"
#include <pthread.h>
#include "receive_interface.h"
#include <unistd.h>
#include "myoled.h"
#include "face.h"
#include "ini.h"

static struct gdevice *pdevice = NULL;

// 数据接收结构体
typedef struct
{
    int msg_len;
    unsigned char *buffer;
    ctr_info_t *ctr_info;
} recv_msg_t;

#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0

// 通过ini配置文件构建设备链表
static int handler(void *user, const char *section, const char *name, const char *value)
{
    struct gdevice *pdev = NULL;

    if (NULL == pdevice)
    {
        pdevice = (struct gdevice *)malloc(sizeof(struct gdevice));
        pdevice->next = NULL;
        memset(pdevice, 0, sizeof(struct gdevice));
        strcpy(pdevice->dev_name, section);
    }
    // 头插法
    else if (0 != strcmp(section, pdevice->dev_name))
    {
        pdev = (struct gdevice *)malloc(sizeof(struct gdevice));
        memset(pdev, 0, sizeof(struct gdevice));
        strcpy(pdev->dev_name, section);
        pdev->next = pdevice;
        pdevice = pdev;
    }

    if (NULL != pdevice)
    {
        if (MATCH(pdevice->dev_name, "key"))
        {
            sscanf(value, "%x", &(pdevice->key));
        }
        else if (MATCH(pdevice->dev_name, "gpio_pin"))
        {
            pdevice->gpio_pin = atoi(value);
        }
        else if (MATCH(pdevice->dev_name, "gpio_mode"))
        {
            if (strcmp(value, "OUTPUT") == 0)
            {
                pdevice->gpio_mode = OUTPUT;
            }
            else if (strcmp(value, "INPUT") == 0)
            {
                pdevice->gpio_mode = INPUT;
            }
        }
        else if (MATCH(pdevice->dev_name, "gpio_status"))
        {
            if (strcmp(value, "LOW") == 0)
            {
                pdevice->gpio_mode = LOW;
            }
            else if (strcmp(value, "HIGH") == 0)
            {
                pdevice->gpio_mode = HIGH;
            }
        }
        else if (MATCH(pdevice->dev_name, "check_face_status"))
        {
            pdevice->check_face_status = atoi(value);
        }
        else if (MATCH(pdevice->dev_name, "voice_set_status"))
        {
            pdevice->voice_set_status = atoi(value);
        }
    }

    return 1;
}

static int receive_init(void)
{

    // 将gdevice.ini文件拷贝到etc目录下
    if (ini_parse("/etc/gdevice.ini", handler, NULL) < 0)
    {
        printf("Can't load 'test.ini'\n");
        return 1;
    }

    myoled_init();
    face_initialize();

    return 1;
}

static void receive_final(void)
{
    face_Finalize();
}

// 控制设备
static void *handle_device(void *arg)
{
    struct gdevice *pcur_dev = NULL;
    recv_msg_t *recv_msg = NULL;
    pthread_t voice_tid; // 语音播报线程
    char sucess_or_failed[20] = "sucess";
    int ret = -1;
    int smoke_status = 0;
    double face_score = 0.0;

    pthread_detach(pthread_self());
    if (NULL != arg)
    {
        recv_msg = (recv_msg_t *)arg;
        printf("%s|%s|%d:0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n", __FILE__, __func__, __LINE__, recv_msg->buffer[0], recv_msg->buffer[1], recv_msg->buffer[2], recv_msg->buffer[3], recv_msg->buffer[4], recv_msg->buffer[5]);
    }

    // AA 55 4x 0X 55 AA
    if (pdevice != NULL && recv_msg->buffer != NULL)
    {
        // 接收的数据4x对应到具体设备
        // 查找设备
        pcur_dev = find_device_by_key(pdevice, recv_msg->buffer[2]);
    }

    // GPIO口设置
    if (pcur_dev != NULL)
    {
        // 接收到的数据0x对应GPIO状态（置1或置0）
        (pcur_dev->gpio_status = recv_msg->buffer[3]) == 0 ? LOW : HIGH;

        // 人脸识别控制GPIO （人脸识别开锁）
        if (1 == pcur_dev->check_face_status)
        {
            face_score = face_category(face_score);
            // 识别成功
            if (face_score > 0.5)
            {
                // 开锁
                ret = set_gpio_gdevice_status(pcur_dev);
                recv_msg->buffer[2] = 0x47;
            }
            else
            {
                recv_msg->buffer[2] = 0x46;
            }
        }
        // 普通控制
        else if (0 == pcur_dev->check_face_status)
        {
            ret = set_gpio_gdevice_status(pcur_dev);
        }

        // 需要语音播报
        if (1 == pcur_dev->voice_set_status)
        {
            if (NULL != recv_msg && NULL != recv_msg->ctr_info && NULL != recv_msg->ctr_info->control_head)
            {
                struct control *pcontrol = recv_msg->ctr_info->control_head;
                while (pcontrol != NULL)
                {
                    // 需要语音播报 链表查找voice控制节点
                    if (strstr(pcontrol->control_name, "voice"))
                    {
                        // 火灾预警特殊处理
                        if (0x45 == recv_msg->buffer[2] && 0x00 == recv_msg->buffer[3])
                        {
                            // 方便设计OLED显示信息
                            smoke_status = 1;
                        }

                        pthread_create(&voice_tid, NULL, pcontrol->set, (void *)recv_msg->buffer);
                        printf("%s|%s|%d:0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n", __FILE__, __func__, __LINE__, recv_msg->buffer[0], recv_msg->buffer[1], recv_msg->buffer[2], recv_msg->buffer[3], recv_msg->buffer[4], recv_msg->buffer[5]);

                        break;
                    }
                    pcontrol = pcontrol->next;
                }
            }
        }

        if (-1 == ret)
        {
            // 设备打开成功或者失败
            memset(sucess_or_failed, 0, sizeof(sucess_or_failed));
            strcpy(sucess_or_failed, "failed");
        }

        // oled显示
        char oled_msg[256];
        memset(oled_msg, 0, sizeof(oled_msg));
        char *cmd_msg = pcur_dev->gpio_status == LOW ? "open" : "close";
        sprintf(oled_msg, "%s %s %s", cmd_msg, pcur_dev->dev_name, sucess_or_failed);
        if (1 == smoke_status)
        {
            // 火灾预警信息特殊处理
            memset(oled_msg, 0, sizeof(oled_msg));
            sprintf(oled_msg, "warning: risk of fire!");
        }
        printf("oled_msg:%s\n", oled_msg);
        myoled_show(oled_msg);

        // 识别成功后关锁
        if (1 == pcur_dev->check_face_status && face_score > 0.5)
        {
            sleep(5);
            pcur_dev->gpio_status = HIGH;
            set_gpio_gdevice_status(pcur_dev);
        }

        pthread_exit(NULL);
    }
}

static void *receive_get(void *arg)
{
    pthread_t tid;
    recv_msg_t *recv_msg = NULL;
    struct mq_attr attr;
    // 暂存接受到的数据
    unsigned char *buffer = NULL;
    int read_len = 0;

    if (NULL != arg)
    {
        // 数据接收结构体初始化
        recv_msg = (recv_msg_t *)malloc(sizeof(recv_msg_t));
        recv_msg->ctr_info = (ctr_info_t *)arg;
        recv_msg->msg_len = -1;
        recv_msg->buffer = NULL;
    }
    else
    {
        pthread_exit(NULL);
    }

    // 获取消息队列属性
    if (mq_getattr(recv_msg->ctr_info->mqd, &attr) == -1)
    {
        pthread_exit(NULL);
    }

    // 按照获取的属性分配空间
    recv_msg->buffer = (unsigned char *)malloc(attr.mq_msgsize);
    buffer = (unsigned char *)malloc(attr.mq_msgsize);
    memset(recv_msg->buffer, 0, attr.mq_msgsize);
    memset(buffer, 0, attr.mq_msgsize);

    while (1)
    {
        // 从消息队列中接收数据
        read_len = mq_receive(recv_msg->ctr_info->mqd, buffer, attr.mq_msgsize, NULL);
        if (-1 == read_len)
        {
            if (errno == EAGAIN)
            {
                printf("queue is empty\n");
            }
            else
            {
                printf("mq_receive error\n");
                break;
            }
        }
        else
        {
            printf("%s|%s|%d:0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n", __FILE__, __func__, __LINE__, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);

            // 符合数据格式
            if (buffer[0] == 0xAA && buffer[1] == 0x55 && buffer[4] == 0x55 && buffer[5] == 0xAA)
            {
                // 拷贝到接受消息结构体（有用数据）
                recv_msg->msg_len = read_len;
                memcpy(recv_msg->buffer, buffer, read_len);
                printf("%s|%s|%d:0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,len=%d\n", __FILE__, __func__, __LINE__, recv_msg->buffer[0], recv_msg->buffer[1], recv_msg->buffer[2], recv_msg->buffer[3], recv_msg->buffer[4], recv_msg->buffer[5], read_len);

                // 接收到数据后控制设备
                pthread_create(&tid, NULL, handle_device, (void *)recv_msg);
            }
        }
    }

    pthread_exit(NULL);
}

struct control receive_control =
    {
        .control_name = "receive",
        .init = receive_init,
        .final = receive_final,
        .get = receive_get,
        .set = NULL,
        .next = NULL};

// receive监听加入链表
struct control *add_receive_to_control(struct control *phead)
{
    return add_interface_to_control_list(phead, &receive_control);
}